﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data.Linq.Mapping;
using System.Linq;
using System.Reflection;
using System.Text;

namespace MyCommon
{
    /// <summary>
    /// 对Object的扩展
    /// </summary>
    public static class ObjectExtentions
    {
        /// <summary>
        /// 将类型为NameValueCollection的集合数据填入实体的对应属性，——郭旭东
        /// </summary>
        /// <param name="model">要填入的实体对象</param>
        /// <param name="collection">类型为NameValueCollection的集合</param>
        /// <param name="matchOne">只否只匹配一项，如果是true，则当实体对象有两个属性映射到同一个数据列，只有一个会被填充</param>
        public static void FillProperty(this object model, NameValueCollection collection, bool matchOne)
        {
            foreach (string item in collection)
            {
                model.FillProperty(item, collection[item], matchOne);
            }
        }
        /// <summary>
        /// 将单个键值对数据填入实体的对应属性，——郭旭东
        /// </summary>
        /// <param name="model">要填入的实体对象</param>
        /// <param name="key">键的名称</param>
        /// <param name="value">数据的值</param>
        /// <param name="matchOne">只否只匹配一项，如果是true，则当实体对象有两个属性映射到同一个数据列，只有一个会被填充</param>
        public static void FillProperty(this object model, string key, object value, bool matchOne)
        {
            var properties = model.GetType().GetProperties();
            foreach (var prop in properties)
            {
                if (IsPropertyMappingDataColumn(prop, key))
                {
                    if (value is System.DBNull)
                    {
                        value = null;
                    }
                    else
                    {
                        var propType = prop.PropertyType;
                        //当实体类属性类型为Nullable时，取得它的泛型参数类型
                        if (propType.IsGenericType)
                        {
                            propType = propType.GetGenericArguments()[0];
                        }
                        if (value.GetType() != propType)
                        {
                            try
                            {
                                value = Convert.ChangeType(value, propType);
                            }
                            catch (Exception e)
                            {
                                throw new InvalidCastException(string.Format("为实体属性赋值时转换数据类型异常，属性名为{0}，要赋给其的数据实际类型为：{1}，值为：{2}", prop.Name, value.GetType(), value), e);
                            }
                        }
                    }
                    prop.SetValue(model, value, null);
                    if (matchOne)
                    {
                        break;
                    }
                }
            }
        }
        /// <summary>
        /// 类的属性是否与指定的数据列名称对应，——郭旭东
        /// </summary>
        /// <param name="prop">属性的反射对象</param>
        /// <param name="columnName">数据列的名称</param>
        static bool IsPropertyMappingDataColumn(PropertyInfo prop, string columnName)
        {
            var attr = Attribute.GetCustomAttribute(prop, typeof(ColumnAttribute)) as ColumnAttribute;
            var mappingName = attr == null ? prop.Name : attr.Name;
            return mappingName.ToUpper() == columnName.ToUpper();
        }
    }
}
